package cn.jbolt.core.gen;

import cn.jbolt.core.util.CodeGenKvDataGenUtil;
import cn.jbolt.core.util.JBoltConsoleUtil;
import com.jfinal.kit.Kv;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.generator.ModelGenerator;
import com.jfinal.plugin.activerecord.generator.TableMeta;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * Model 生成器
 */
public class JBoltModelGenerator extends ModelGenerator {
    private String dataSourceConfigName;
    private String dbType;
    private String idGenMode;

    public JBoltModelGenerator(String dataSourceConfigName, String dbType, String idGenMode, String modelPackageName,
                               String baseModelPackageName, String modelOutputDir) {
        super(modelPackageName, baseModelPackageName, modelOutputDir);
        this.dataSourceConfigName = dataSourceConfigName;
        this.dbType = dbType;
        this.idGenMode = idGenMode;
    }

    @Override
    protected void initEngine() {
        super.initEngine();
//        engine.setStaticFieldExpression(true);
//        engine.setStaticMethodExpression(true);
        engine.setDevMode(true);
        engine.addSharedObject("CodeGenKvDataGenUtil", new CodeGenKvDataGenUtil());
        setTemplate("/gentpl/model_template.jf");
    }

    @Override
    public void generate(List<TableMeta> tableMetas) {
        JBoltConsoleUtil.printMessage("-------------------------Model-------------------------");
        JBoltConsoleUtil.printMessageWithDate(" Generate Model :Starting ...");
        JBoltConsoleUtil.printMessageWithDate(" Model Output Dir: " + modelOutputDir);
        JBoltConsoleUtil.printMessageWithDate(" JBolt Model Generator is Working...");

        for (TableMeta tableMeta : tableMetas) {
            genModelContent(tableMeta);
        }
        writeToFile(tableMetas);

        JBoltConsoleUtil.printMessageWithDate(" Generate Model :Done ...");
    }

    @Override
    protected void genModelContent(TableMeta tableMeta) {
        JBoltConsoleUtil.printMessageWithDate(" Generate Model:" + modelPackageName + "." + tableMeta.modelName);
        Kv data = Kv.by("modelPackageName", modelPackageName);
        data.set("baseModelPackageName", baseModelPackageName);
        data.set("generateDaoInModel", generateDaoInModel);
        data.set("tableMeta", tableMeta);
        data.set("dataSource", dataSourceConfigName);
        data.set("dbType", dbType);
        data.set("idGenMode", "JBoltIDGenMode." + idGenMode.toUpperCase());
        data.set("translates", JBoltProjectGenConfig.translates);
        data.set("importClasses", proessImportClasses());
        if (JBoltProjectGenConfig.autoCacheEnable) {
            data.set("autoCacheEnable", JBoltProjectGenConfig.autoCacheEnable);
            data.set("idCacheEnable", JBoltProjectGenConfig.idCacheEnable);
            data.set("keyCacheEnable", JBoltProjectGenConfig.keyCacheEnable);
            data.set("keyCacheColumn", JBoltProjectGenConfig.keyCacheColumn);
            data.set("keyCacheBindColumn", JBoltProjectGenConfig.keyCacheBindColumn);
        }

        String ret = engine.getTemplate(template).renderToString(data);
        tableMeta.modelContent = ret;
    }

    private List<String> proessImportClasses() {
        List<String> list = new ArrayList<>();
        if(JBoltProjectGenConfig.translates!=null && JBoltProjectGenConfig.translates.size()>0){
            String translateType;
            for(Model m : JBoltProjectGenConfig.translates){
                translateType = m.getStr("translate_type");
                if(translateType!=null){
                    switch (translateType){
                        case "sys_dic_id":
                        case "sys_dic_sn":
                            list.add("import cn.jbolt.core.cache.JBoltDictionaryCache;");
                            break;
                        case "sys_user_id_to_username":
                        case "sys_user_id_to_name":
                        case "sys_user_username_to_name":
                            list.add("import cn.jbolt.core.cache.JBoltUserCache;");
                            break;
                        case "enum":
                            list.add("import cn.jbolt.core.enumutil.JBoltEnum;");
                            break;
                        case "kv_data":
                            list.add("import com.jfinal.kit.Kv;");
                            break;
                    }
                    if(translateType.equals("cache") ||translateType.equals("enum") ||translateType.equals("static_method") || translateType.equals("service_method")){
                        String ic = getTranslateImportClass(m.getStr("translate_use_value"));
                        if(StrKit.notBlank(ic)){
                            list.add(ic);
                        }
                    }
                }
            }
        }
        return list;
    }


    public String getTranslateImportClass(String translateUseValue){
        if(StrKit.isBlank(translateUseValue)){
            return null;
        }
        if(translateUseValue.contains(":")){
            translateUseValue = translateUseValue.substring(0,translateUseValue.lastIndexOf(":"));
        }
        return "import " + translateUseValue +";";
    }

    /**
     * 若 model 文件存在，则不生成，以免覆盖用户手写的代码
     */
    @Override
    protected void writeToFile(TableMeta tableMeta) throws IOException {
        File dir = new File(modelOutputDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        String target = modelOutputDir + File.separator + tableMeta.modelName + ".java";

        File file = new File(target);
        if (file.exists()) {
            if(!JBoltProjectGenConfig.cover){
                //如果存在了 并且未设置覆盖 就不处理了
                return;
            }
        }

        try (OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) {
            osw.write(tableMeta.modelContent);
        }
    }
}
